/*
 * Copyright 2006-2007 - Chris Maki
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.theserverside.blog.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.Cascade;

@Entity
@Table(name = "BLOG_POST")
@AttributeOverrides( { @AttributeOverride(name = "id", column = @Column(name = "BP_ID")),
    @AttributeOverride(name="version", column=@Column(name="BP_VERSION")),
    @AttributeOverride(name="dateCreated", column=@Column(name="BP_DATE_CREATED")),
    @AttributeOverride(name="dateUpdated", column=@Column(name="BP_DATE_UPDATED"))
    })
@AssociationOverrides( {
    @AssociationOverride(name="createdByUser", joinColumns=@JoinColumn(name="BP_CREATED_BY_USER_ID")),
    @AssociationOverride(name="updatedByUser", joinColumns=@JoinColumn(name="BP_UPDATED_BY_USER_ID"))
})
@NamedQueries( { 
    @NamedQuery(name = "blogPost.cratedByUser", query = "SELECT DISTINCT p FROM BlogPost p WHERE p.createdByUser = ?1"),
    // determine the number of posts a User has made
    @NamedQuery(name = "blogPost.postCreated", query = "SELECT COUNT(p) FROM BlogPost p WHERE p.createdByUser = ?1") 
})
public class BlogPost extends ModelBase implements Serializable {

    private static final long serialVersionUID = -2222782732859512839L;

    @Lob
    @Column(name = "BP_CONTENT")
    private String content;

    @Column(name="BP_TITLE")
    private String title;

    @Column(name = "BP_EDIT_COUNT")
    private Integer editCount;

    @Column(name = "BP_TAGS")
    private String tags;

    // we use the DELETE_ORPHAN cascade type to make sure comments are deleted
    // when they are removed from the blog post
    @OneToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE}, fetch=FetchType.EAGER, mappedBy="blogPost")
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    private List<Comment> comments = new ArrayList<Comment>();

    
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Integer getEditCount() {
        return editCount;
    }

    public void setEditCount(Integer editCount) {
        this.editCount = editCount;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTags() {
        return tags;
    }

    /**
     * Returns an immutable list of Comments. If you want to modify the comments
     * for a blog post, use <code>addComment</code> or
     * <code>removeComment</code> instead.
     * 
     * @return an immutable list of comments
     */
    public List<Comment> getComments() {
        return Collections.unmodifiableList(comments);
    }
    /**
     * Adds a comment to the blog post's list of comments 
     * @param comment the comment to add
     */
    public void addComment(Comment comment) {
        if (comment == null) throw new IllegalArgumentException("comment is null!");
        if (comment.getBlogPost() != null) {
            comment.getBlogPost().comments.remove(comment);
        }
        if (comment.getParent() != null) {
            comment.getParent().removeChildComment(comment);
        }
        // associate comment with this blog post
        comment.setBlogPost(this);
        comments.add(comment);
    }
    
    public void removeComment(Comment comment) {
        if (comment == null) throw new IllegalArgumentException("comment is null!");

        // only disconnect comments that are associated with this instance
        if (comment.getBlogPost().equals(this)) {
            comments.remove(comment);
        }
    }

    @Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + ((content == null) ? 0 : content.hashCode());
        result = PRIME * result + ((title == null) ? 0 : title.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (!(obj instanceof BlogPost)) return false;
        final BlogPost other = (BlogPost) obj;
        if (title == null) {
            if (other.getTitle() != null) return false;
        }
        else if (!title.equals(other.getTitle())) return false;
        if (content == null) {
            if (other.getContent() != null) return false;
        }
        else if (!content.equals(other.content)) return false;

        return true;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this)
          .append("id", getId())
          .append("title", title)
          .append("content", content)
          .append("dateCreated", getDateCreated())
          .append("dateUpdated", getDateUpdated())
          .append("version", getVersion())
          .append("title", getTitle())
          .append("content", getContent())
          .append("tags", getTags())
          .toString();
    }


    

}
